#include "EbnCompetenceModule.h"
#include "EbnAction.h"
#include "EbnModel.h"



CEbnCompetenceModule::CEbnCompetenceModule(CEbnAction * pAction)
{
    mpAction = pAction;
    mModuleActivation = 0;
    mExternActivation = 0;
    mSpreadActivation = 0;
    mPreviousActivation = 0;
    mSelectedToExecute = false;
    mExecutability = 1;

    mPredecessorLinkToCnt = 0;
    mSuccessorLinkToCnt = 0;
    mConflictorLinkToCnt = 0;
    mReceptorLinkToCnt = 0;
    mGoalLinkToCnt = 0;
}

CEbnCompetenceModule::~CEbnCompetenceModule(void)
{
    mpAction = NULL;
    clearConditions();
    clearEffects();
}

string CEbnCompetenceModule::getActionName()
{
    if (mpAction)
    {
        return mpAction->getName();
    }
    else
    {
        return NULL;
    }
}

CEbnCondition * CEbnCompetenceModule::addCondition(CEbnWorldState * worldState, bool positive)
{
    CEbnCondition * pCondition = new CEbnCondition(worldState, positive);
    addCondition(pCondition);

    return pCondition;
}

CEbnEffect * CEbnCompetenceModule::addPostEffect(CEbnWorldState * worldState, bool positive)
{
    CEbnEffect * pEffect = new CEbnEffect(worldState, positive);
    addPostEffect(pEffect);

    return pEffect;
}

void CEbnCompetenceModule::addCondition(CEbnCondition * pCondition)
{
    bool exist = hasCondition(pCondition);

    if (exist == false)
    {
        mConditions.push_back(pCondition);
    }
}
	
void CEbnCompetenceModule::addPostEffect(CEbnEffect * pEffect)
{
    bool exist = hasEffect(pEffect);

    if (exist == false)
    {
        mEffects.push_back(pEffect);
    }
}

bool CEbnCompetenceModule::hasCondition(CEbnCondition * pCondition)
{
    vector<CEbnCondition *>::iterator itCondition;
    for (itCondition = mConditions.begin(); itCondition != mConditions.end(); itCondition++)
    {
        if((*itCondition) == pCondition)
        {
            return true;
        }
    }

    return false;
}

CEbnCondition * CEbnCompetenceModule::getCondition(string conditionName)
{
    vector<CEbnCondition *>::iterator itCondition;
    for (itCondition = mConditions.begin(); itCondition != mConditions.end(); itCondition++)
    {
        if((*itCondition)->getName().compare(conditionName) == 0)
        {
            return (*itCondition);
        }
    }

    return NULL;
}

bool CEbnCompetenceModule::hasEffect(CEbnEffect * pEffect)
{
    vector<CEbnEffect *>::iterator itEffect;
    for (itEffect = mEffects.begin(); itEffect != mEffects.end(); itEffect++)
    {
        if((*itEffect) == pEffect)
        {
            return false;
        }
    }

    return false;
}

CEbnEffect * CEbnCompetenceModule::getPostEffect(string effectName)
{
    vector<CEbnEffect *>::iterator itEffect;
    for (itEffect = mEffects.begin(); itEffect != mEffects.end(); itEffect++)
    {
        if ((*itEffect)->getName().compare(effectName) == 0)
        {
            return (*itEffect);
        }
    }

    return NULL;
}

int CEbnCompetenceModule::getConditionCount(void)
{
	return (int)mConditions.size();
}

CEbnCondition * CEbnCompetenceModule::getCondition(int index)
{
    if ((index < 1) || (index > getConditionCount()))
    {
        return NULL;
    }

    return mConditions.at(index - 1);
}

int CEbnCompetenceModule::getPostEffectCount(void)
{
    return (int)mEffects.size();
}

CEbnEffect * CEbnCompetenceModule::getPostEffect(int index)
{
    if ((index < 1) || (index > getPostEffectCount()))
    {
        return NULL;
    }

    return mEffects.at(index - 1);
}

void CEbnCompetenceModule::addToLink(CEbnLink * pLink)
{
    bool exist = hasToLink(pLink);

    if (exist == false)
    {
        mToLinks.push_back(pLink);
    }
}

void CEbnCompetenceModule::addFromLink(CEbnLink * pLink)
{
    bool exist = hasFromLink(pLink);

    if (exist == false)
    {
        mFromLinks.push_back(pLink);
    }
}

bool CEbnCompetenceModule::hasToLink(CEbnLink * pLink)
{
    vector<CEbnLink *>::iterator itLink;
    for (itLink = mToLinks.begin(); itLink != mToLinks.end(); itLink++)
    {
        if ((*itLink) == pLink)
        {
            return true;
        }
    }

    return false;
}

bool CEbnCompetenceModule::hasFromLink(CEbnLink * pLink)
{
    vector<CEbnLink *>::iterator itLink;
    for (itLink = mFromLinks.begin(); itLink != mFromLinks.end(); itLink++)
    {
        if ((*itLink) == pLink)
        {
            return true;
        }
    }

    return false;
}

void CEbnCompetenceModule::resetActivation(void)
{
    mModuleActivation = 0;
}

void CEbnCompetenceModule::setActivation(float activation)
{
    mModuleActivation = activation;
}

float CEbnCompetenceModule::getActivation(void)
{
    return mModuleActivation;
}

float CEbnCompetenceModule::updateActivation(void)
{
    mPreviousActivation = calcPreviousActivation();
    mExternActivation = calcExternActivation();
    mSpreadActivation = calcSpreadActivation();
    float activation = mPreviousActivation
            + mExternActivation
            + mSpreadActivation;

    setActivation(activation);

    return activation;

}

int CEbnCompetenceModule::getToLinkCount(void)
{
    return (int)mToLinks.size();
}

CEbnLink * CEbnCompetenceModule::getToLink(int index)
{
    if ((index < 1) || (index > getToLinkCount()))
    {
        return NULL;
    }

    return mToLinks.at(index - 1);

}

void CEbnCompetenceModule::addActivationHist(float activation)
{
    mActivationHist.push_back(activation);
}

int CEbnCompetenceModule::getFromLinkCount(void)
{
    return (int)mFromLinks.size();
}

CEbnLink * CEbnCompetenceModule::getFromLink(int index)
{
    if ((index < 1) || (index > getFromLinkCount()))
    {
        return NULL;
    }

    return mFromLinks.at(index - 1);

}

float CEbnCompetenceModule::getActivationHist(int time)
{
	if (time<=0)
	{
		return 0.0f;
	}

	return mActivationHist.at(time-1);
}

float CEbnCompetenceModule::getPostEffectExpectation(string effectName)
{
    CEbnEffect * pEffect = getPostEffect(effectName);

    if (pEffect)
    {
        return pEffect->getExpectation();
    }

    return 0;
}

float CEbnCompetenceModule::getExecutability(void)
{
    return mExecutability;
}

void CEbnCompetenceModule::updateExecutability(void)
{	
    // T-norm for calculating executability
    // here multiplication is used
    mExecutability = 1;

    vector<CEbnCondition *>::iterator itCondition;
    for (itCondition = mConditions.begin(); itCondition != mConditions.end(); itCondition++)
    {
        mExecutability = mExecutability * (* itCondition)->getValue();
    }
}

bool CEbnCompetenceModule::executeModule()
{
    setToExecute(true);

    if (mpAction)
    {
        mpAction->action();
    }

    /*
    // Set all post effect
    vector<CEbnEffect *>::iterator itEffect;
    for (itEffect = mEffects.begin(); itEffect != mEffects.end(); itEffect++)
    {
        (*itEffect)->setWorldState();
    }
     */

    return true;

}

void CEbnCompetenceModule::setToExecute(bool execute)
{
    mSelectedToExecute = execute;
}

bool CEbnCompetenceModule::isSelectedToExecute()
{
    return mSelectedToExecute;
}

float CEbnCompetenceModule::calcPreviousActivation()
{
    float decayedActivation = GETPARAM()->getInertiaOfActivation() * mModuleActivation;
    return decayedActivation;
}

float CEbnCompetenceModule::calcExternActivation()
{
    float externActivation = 0;
    CEbnLink * pLink = NULL;
    CEbnGoalLink * pGoalLink = NULL;
    CEbnReceptorLink * pReceptorLink = NULL;
    vector<CEbnLink *>::iterator itLink;

    for (itLink = mToLinks.begin(); itLink != mToLinks.end(); itLink++)
    {
        pLink = (* itLink);

        if (GOAL_LINK == pLink->getLinkType())
        {
            pGoalLink = (CEbnGoalLink *) pLink;
            externActivation += pGoalLink->getActivation();

        }
        else if (RECEPTOR_LINK == pLink->getLinkType())
        {
            pReceptorLink = (CEbnReceptorLink*) pLink;
            externActivation += pReceptorLink->getActivation();

        }
    }

    return externActivation;

}

float CEbnCompetenceModule::calcSpreadActivation()
{
    float spreadActivation = 0;
    CEbnLink * pLink = NULL;
    CEbnPredecessorLink * pPredecessorLink = NULL;
    CEbnSuccessorLink * pSuccessorLink = NULL;
    CEbnConflictorLink * pConflictorLink = NULL;
    vector<CEbnLink *>::iterator itLink;

    for (itLink = mToLinks.begin(); itLink != mToLinks.end(); itLink++)
    {
        pLink = (* itLink);

        if (PREDECCESSOR_LINK == pLink->getLinkType())
        {
            pPredecessorLink = (CEbnPredecessorLink *) pLink;
            spreadActivation += pPredecessorLink->getActivation();

        }
        else if ((SUCCESSOR_LINK) == pLink->getLinkType())
        {
            pSuccessorLink = (CEbnSuccessorLink *) pLink;
            spreadActivation += pSuccessorLink->getActivation();
        }
        else if (CONFLICTOR_LINK == pLink->getLinkType())
        {
            pConflictorLink = (CEbnConflictorLink *) pLink;
            spreadActivation += pConflictorLink->getActivation();
        }
    }

    return spreadActivation;
}

bool CEbnCompetenceModule::hasAction(CEbnAction * pAction)
{
    if (mpAction == pAction)
    {
        return true;
    }

    return false;
}

void CEbnCompetenceModule::clearConditions(void)
{
    vector<CEbnCondition *>::iterator itCondition;
    CEbnCondition * pCondition = NULL;

    for (itCondition = mConditions.begin(); itCondition != mConditions.end(); itCondition++)
    {
        pCondition = (* itCondition);

        delete pCondition;
        pCondition = NULL;
    }

    mConditions.clear();
}

void CEbnCompetenceModule::clearEffects(void)
{
    vector<CEbnEffect *>::iterator itEffect;
    CEbnEffect * pEffect = NULL;

    for (itEffect = mEffects.begin(); itEffect != mEffects.end(); itEffect++)
    {
        pEffect = (* itEffect);

        delete pEffect;
        pEffect = NULL;
    }

    mEffects.clear();
}

int CEbnCompetenceModule::getLinkCnt(LinkType type)
{
    switch(type)
    {
        case PREDECCESSOR_LINK:
            return mPredecessorLinkToCnt;
        case SUCCESSOR_LINK:
            return mSuccessorLinkToCnt;
        case CONFLICTOR_LINK:
            return mConflictorLinkToCnt;
        case RECEPTOR_LINK:
            return mReceptorLinkToCnt;
        case GOAL_LINK:
            return mGoalLinkToCnt;
    }

    return 0;
}

void CEbnCompetenceModule::updateLinkCnt(void)
{
    vector<CEbnLink *>::iterator it;

    // reset link count
    mPredecessorLinkToCnt = 0;
    mSuccessorLinkToCnt = 0;
    mConflictorLinkToCnt = 0;
    mReceptorLinkToCnt = 0;
    mGoalLinkToCnt = 0;

    for(it = mToLinks.begin(); it != mToLinks.end(); it++)
    {
        switch((*it)->getLinkType())
        {
            case PREDECCESSOR_LINK:
                mPredecessorLinkToCnt++;
                break;
            case SUCCESSOR_LINK:
                mSuccessorLinkToCnt++;
                break;
            case CONFLICTOR_LINK:
                mConflictorLinkToCnt++;
                break;
            case RECEPTOR_LINK:
                mReceptorLinkToCnt++;
                break;
            case GOAL_LINK:
                mGoalLinkToCnt++;
                break;
            case NULL_LINK:
                break;
        }
    }
}
